package com.emser.unc.server;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.jdo.JDOCanRetryException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.Transaction;

import org.datanucleus.store.appengine.query.JDOCursorHelper;

import com.emser.unc.serializable.NoSaleReportDTO;
import com.emser.unc.serializable.ProductSoldDTO;
import com.emser.unc.serializable.ResultDTO;
import com.emser.unc.serializable.SaleReportDTO;
import com.emser.unc.server.domain.NoSaleReport;
import com.emser.unc.server.domain.ProductSold;
import com.emser.unc.server.domain.SaleReport;
import com.emser.unc.server.domain.SaleReportIndex;
import com.emser.unc.server.domain.Seller;
import com.emser.unc.server.domain.UserAccount;
import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

public class AppLibReports {
	private static final int NUM_RETRIES = 5;
	public static boolean addSaleReportDatastore(SaleReportDTO saleReportDTO){
		Transaction tx = null;
	    boolean result = false;
	    Iterator<ProductSoldDTO> iterator = saleReportDTO.getProductsSold().iterator();
	    SaleReport saleReport = createSaleReportDB(saleReportDTO);
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query q = pm.newQuery(Seller.class);
		q.setFilter("userName == :userNameSeller");
		q.setUnique(true);
	    try {
	      for (int i = 0; i < NUM_RETRIES; i++) {
	        tx = pm.currentTransaction();
	        tx.begin();
	        Seller s = (Seller) q.execute(saleReportDTO.getSellerUserName());
			s.getUserA().getSaleReports().add(saleReport);
			saleReport.setUserAName(s.getUserA().getUserName().getName());
			pm.makePersistent(saleReport);
			saleReport.setId();
			KeyFactory.Builder keyBuilder = new KeyFactory.Builder(saleReport.getKey());
        	keyBuilder.addChild(SaleReportIndex.class.getSimpleName(), saleReport.getKey().getId());
        	Key ckey = keyBuilder.getKey();
			SaleReportIndex saleReportI = new SaleReportIndex(ckey);
			while(iterator.hasNext()){
				ProductSoldDTO productSoldDTO = iterator.next();
				ProductSold pSold = new ProductSold();
				pSold.setQuantity(productSoldDTO.getQuantity());
				pSold.setTitle(productSoldDTO.getTitle());
				pSold.setUnitPrice(productSoldDTO.getUnitPrice());
				pSold.setIdProduct(productSoldDTO.getCode());
				saleReportI.getProductsS().add(pSold);
			}
			pm.makePersistent(saleReportI);
	        try {
	          tx.commit();
	          result = true;
	          break;
	        }
	        catch (JDOCanRetryException e1) {
	          if (i == (NUM_RETRIES - 1)) {
	            throw e1;
	          }
	        }
	      } 
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	      result = false;
	    }
	    finally {
	      if (tx.isActive()) {
	        tx.rollback();
	      }
	      pm.close();
	      q.closeAll();
	    }
		return result;
	}
	
	@SuppressWarnings("unchecked")
	public static ResultDTO<SaleReportDTO> getSaleReports(String cursorString, int range,String userAccountName) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
	    Transaction tx = null;
	    ResultDTO<SaleReportDTO> result = null;
	    List<SaleReport> reportsList = null;
		List<SaleReport> reportsListCopy = null;
		Key userName = KeyFactory.createKey(UserAccount.class.getSimpleName(), userAccountName);
	    Query q = pm.newQuery(SaleReport.class);
	    q.setFilter("userA == :userName");
	    if (cursorString != null) {
        	Cursor cursor = Cursor.fromWebSafeString(cursorString);
        	Map<String, Object> extensionMap = new HashMap<String,
        	Object>();
        	extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
        	q.setExtensions(extensionMap);
        }
	    q.setRange(0, range);
		try {
	      for (int i = 0; i < NUM_RETRIES; i++) {
	        tx = pm.currentTransaction();
	        tx.begin();
	        reportsList = (List<SaleReport>) q.execute(userName);
	        if(reportsList != null){
	        	reportsListCopy = (List<SaleReport>)pm.detachCopyAll(reportsList);
	        	Cursor cursor = JDOCursorHelper.getCursor(reportsList);
		        cursorString = cursor.toWebSafeString();
		        
	        }
	        else {
	        	cursorString = null;
	        }
	        
	        try {
	          tx.commit();
	          break;
	        }
	        catch (JDOCanRetryException e1) {
	          if (i == (NUM_RETRIES - 1)) {
	            throw e1;
	          }
	        }
	      } 
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	    }
	    finally {
	      if (tx.isActive()) {
	        tx.rollback();
	      }
	      pm.close();
	    }
	    if(reportsListCopy != null){
	    	result = new ResultDTO<SaleReportDTO>();
	    	result.setList(toDTOSReports(reportsListCopy));
	    	result.setCursorString(cursorString);
        	return result;
	    }
	    else return null;
	}
	
	public static ArrayList<SaleReportDTO> toDTOSReports(List<SaleReport> saleReports){
		ArrayList<SaleReportDTO> saleReportsDTO = new ArrayList<SaleReportDTO>();
        for(int i = 0;i<saleReports.size();i++)
        	saleReportsDTO.add(SaleReport.toDTO(saleReports.get(i)));        	       
        return saleReportsDTO;
	}
	
	public static boolean addNoSaleReportDatastore(NoSaleReportDTO noSaleReportDTO){
		Seller sellerDB = null;
		Transaction tx = null;
	    boolean result = false;
	    NoSaleReport saleNoReport = new NoSaleReport();
	    saleNoReport.setCustomerID(noSaleReportDTO.getCustomerID());
	    saleNoReport.setSellerUserName(noSaleReportDTO.getSellerUserName());
	    saleNoReport.setCode(noSaleReportDTO.getCode());
	    saleNoReport.setDate(new Date());
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query q = pm.newQuery(Seller.class);
		q.setFilter("userName == :userN");
		q.setUnique(true);
	    try {
	      for (int i = 0; i < NUM_RETRIES; i++) {
	        tx = pm.currentTransaction();
	        tx.begin();
	        sellerDB = (Seller)q.execute(noSaleReportDTO.getSellerUserName());
	        if(sellerDB != null){
	        	sellerDB.getUserA().getSaleNoReports().add(saleNoReport);
	        	pm.makePersistent(saleNoReport);
	        	saleNoReport.setId();
	        }
	        try {
	          tx.commit();
	          result = true;
	          break;
	        }
	        catch (JDOCanRetryException e1) {
	          if (i == (NUM_RETRIES - 1)) {
	            throw e1;
	          }
	        }
	      } 
	    }
	    catch (Exception e) {
	    	result = false;
	    	e.printStackTrace();
	    }
	    finally {
	      if (tx.isActive()) {
	        tx.rollback();
	      }
	      pm.close();
	      q.closeAll();
	    }
		return result;
	}
	
	@SuppressWarnings("unchecked")
	public static ResultDTO<NoSaleReportDTO> getSaleNoReports(String cursorString, int range,String userAccountName) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
	    Transaction tx = null;
	    ResultDTO<NoSaleReportDTO> result;
	    List<NoSaleReport> reportsList = null;
	    List<NoSaleReport> reportsListCopy = null;
	    Key userName = KeyFactory.createKey(UserAccount.class.getSimpleName(), userAccountName);
	    Query q = pm.newQuery(NoSaleReport.class);
	    q.setFilter("userA == :userName");
	    if (cursorString != null) {
        	Cursor cursor = Cursor.fromWebSafeString(cursorString);
        	Map<String, Object> extensionMap = new HashMap<String,
        	Object>();
        	extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
        	q.setExtensions(extensionMap);
        }
	    q.setRange(0, range);
	    try {
	      for (int i = 0; i < NUM_RETRIES; i++) {
	        tx = pm.currentTransaction();
	        tx.begin();
	        reportsList = (List<NoSaleReport>) q.execute(userName);	        
	        if(reportsList != null){
	        	reportsListCopy = (List<NoSaleReport>) pm.detachCopyAll(reportsList);
	        		Cursor cursor = JDOCursorHelper.getCursor(reportsList);
	        		cursorString = cursor.toWebSafeString();
	        }
	        else {
	        	cursorString = null;
	        }	
	        try {
	          tx.commit();
	          break;
	        }
	        catch (JDOCanRetryException e1) {
	          if (i == (NUM_RETRIES - 1)) {
	            throw e1;
	          }
	        }
	      } 
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	      result = null;
	    }
	    finally {
	      if (tx.isActive()) {
	        tx.rollback();
	      }
	      pm.close();
	    }
	    if(reportsListCopy!=null){
	    	result = new ResultDTO<NoSaleReportDTO>();
        	result.setCursorString(cursorString);
        	result.setList(toDTONSReports(reportsListCopy));
        	return result;
		}
	    else return null;
		
	}
	
	public static ArrayList<NoSaleReportDTO> toDTONSReports(List<NoSaleReport> noSaleReports){
		ArrayList<NoSaleReportDTO> noSaleReportsDTO = new ArrayList<NoSaleReportDTO>();
        for(int i = 0;i<noSaleReports.size();i++)
        	noSaleReportsDTO.add(NoSaleReport.toDTO(noSaleReports.get(i)));
        return noSaleReportsDTO;
	}
	
	@SuppressWarnings("unchecked")
	public static Integer getSaleReportCount(String userAccountName){
		PersistenceManager pm = PMF.get().getPersistenceManager();
	    Transaction tx = null;
	    Integer reportsCount = 0;
	    List<SaleReport> saleReportList = new ArrayList<SaleReport>();
	    Key userKey = KeyFactory.createKey(UserAccount.class.getSimpleName(), userAccountName);
	    Query q = pm.newQuery(SaleReport.class);
	    q.setFilter("userA == :userName");
	    try {
	      for (int i = 0; i < NUM_RETRIES; i++) {
	        tx = pm.currentTransaction();
	        tx.begin();
	        saleReportList =(List<SaleReport>)q.execute(userKey);
	        if(saleReportList != null && !saleReportList.isEmpty())
	        	reportsCount = saleReportList.size();
	        try {
	          tx.commit();
	          break;
	        }
	        catch (JDOCanRetryException e1) {
	          if (i == (NUM_RETRIES - 1)) {
	            throw e1;
	          }
	        }
	      } 
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	      return null;
	    }
	    finally {
	      if (tx.isActive()) {
	        tx.rollback();
	      }
	      pm.close();
	    }
		return reportsCount;
	}
	
	@SuppressWarnings("unchecked")
	public static List<SaleReport> getSaleReports(List<Long> saleReportsIds){
		List<SaleReport> saleReports = null;
		List<SaleReport> result = null;
		if(saleReportsIds.isEmpty()||saleReportsIds ==null)
			return result;
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query q = pm.newQuery("select from " +SaleReport.class.getName()+" where id == :ids"); 
		try{
			saleReports = (List<SaleReport>)q.execute(saleReportsIds);
			if(saleReports != null)
				result = (List<SaleReport>)pm.detachCopyAll(saleReports);
		}catch(Exception e){
			e.printStackTrace();
			return null;
		}
		finally{
			q.closeAll();
			pm.close();			
		}
		return result; 
		
	}
	
	@SuppressWarnings("unchecked")
	public static Integer getNoSaleReportCount(String userAccountName){
	    Integer result = 0;
	    PersistenceManager pm = PMF.get().getPersistenceManager();
	    Transaction tx = null;
	    List<NoSaleReport> reportsList = null;
	    Key userName = KeyFactory.createKey(UserAccount.class.getSimpleName(), userAccountName);
	    Query q = pm.newQuery(NoSaleReport.class);
	    q.setFilter("userA == :userName");
	    try {
	      for (int i = 0; i < NUM_RETRIES; i++) {
	        tx = pm.currentTransaction();
	        tx.begin();
	        reportsList = (List<NoSaleReport>) q.execute(userName);	        
	        if(reportsList != null)
	        	result = reportsList.size();
	        try {
	          tx.commit();
	          break;
	        }
	        catch (JDOCanRetryException e1) {
	          if (i == (NUM_RETRIES - 1)) {
	            throw e1;
	          }
	        }
	      } 
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	      result = null;
	    }
	    finally {
	      if (tx.isActive()) {
	        tx.rollback();
	      }
	      pm.close();
	    }
		return result;
	}
	
	@SuppressWarnings("unchecked")
	public static boolean deleteNoSaleReports(String userAccountName, ArrayList<Long> reportsIds) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		boolean result = false;
		Transaction tx = null;
	    List<NoSaleReport> reportsDB = null;
        Key userName = KeyFactory.createKey(UserAccount.class.getSimpleName(), userAccountName);
	    Query q = pm.newQuery(NoSaleReport.class);
	    q.setFilter("id == :ids && userA == :userName");
	    try {
	    	for (int i = 0; i < NUM_RETRIES; i++) {
		        tx = pm.currentTransaction();
		        tx.begin();
		        reportsDB = (List<NoSaleReport>)q.execute(reportsIds,userName);
		        if(reportsDB != null){
		        	pm.deletePersistentAll(reportsDB);
		        	result = true;
	    		}
			 try {
		          tx.commit();		          
		          break;
		        }
		        catch (JDOCanRetryException e1) {
		          if (i == (NUM_RETRIES - 1)) {
		            throw e1;
		          }
		        }
	    	}
	    }
	    catch (Exception e) {
	    	e.printStackTrace();
	    	result = false;
	    }
	    finally {
	    	q.closeAll();
	    	pm.close(); 
	    }   
		return result;
	}
	
	public static boolean deleteSaleReport(String userAName,SaleReport saleReport){
		SaleReportIndex saleReportIndex;
		boolean result = false;
		PersistenceManager pm = PMF.get().getPersistenceManager();
		KeyFactory.Builder keyBuilder = new KeyFactory.Builder(UserAccount.class.getSimpleName(), userAName);
    	keyBuilder.addChild(SaleReport.class.getSimpleName(), saleReport.getId()).addChild(SaleReportIndex.class.getSimpleName(), saleReport.getId());
    	Key ckey = keyBuilder.getKey();
		Transaction tx = null;
		try{
			for (int i = 0; i < NUM_RETRIES; i++) {
		        tx = pm.currentTransaction();
		        tx.begin();
		        try{
		        	saleReportIndex = pm.getObjectById(SaleReportIndex.class, ckey);
		        	pm.deletePersistent(saleReportIndex);
		        }catch(javax.jdo.JDOObjectNotFoundException e){}
		        pm.deletePersistent(saleReport);
		        result = true;
		        try {
			         tx.commit();			         
			         break;
			    }
			    catch (JDOCanRetryException e1) {
			         if (i == (NUM_RETRIES - 1)) {
			           throw e1;
			         }
			    }
		      }
		}
		catch (Exception e) {			
			e.printStackTrace();
			result = false;
		}
		finally {
			if (tx.isActive()) {
			   tx.rollback();
			}
			pm.close();
		}
		return result;
	}
	
	public static boolean deleteSaleReports(String userAccountName, ArrayList<Long> reportsIds) {
		boolean result = false;
	    List<SaleReport> saleReportsDB = null;
	    saleReportsDB = getSaleReports(reportsIds);
	    if(saleReportsDB != null){
	    	result = true;
	    	Iterator<SaleReport> iterator = saleReportsDB.iterator();
	    	while((iterator.hasNext())&&(result)){
	    		SaleReport saleReport = iterator.next();
	    		result = deleteSaleReport(userAccountName,saleReport);
	    	}
	    }
        return result;
	}
	
	@SuppressWarnings("unchecked")
	public static ResultDTO<ProductSoldDTO> getProductsSold(String cursorString, int range,String userAName,Long idReport){
		PersistenceManager pm = PMF.get().getPersistenceManager();
		ResultDTO<ProductSoldDTO> result = null;
		List<ProductSold> productsSolds = null,productsSoldsCopy = null;
		ArrayList<ProductSoldDTO> temp = new ArrayList<ProductSoldDTO>();
		KeyFactory.Builder keyBuilder =
			new KeyFactory.Builder(UserAccount.class.getSimpleName(), userAName);
			keyBuilder.addChild(SaleReport.class.getSimpleName(), idReport).addChild(SaleReportIndex.class.getSimpleName(), idReport);
			Key reportKey = keyBuilder.getKey();
		Query q = pm.newQuery(ProductSold.class);
		q.setFilter("saleRIndex == :reportKey");
		q.setRange(0, range);
		if (cursorString != null) {
        	Cursor cursor = Cursor.fromWebSafeString(cursorString);
        	Map<String, Object> extensionMap = new HashMap<String,Object>();
        	extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
        	q.setExtensions(extensionMap);
        }	
		try{
			productsSolds = (List<ProductSold>)q.execute(reportKey);
			if(productsSolds != null){
				productsSoldsCopy = (List<ProductSold>) pm.detachCopyAll(productsSolds);
				Cursor cursor = JDOCursorHelper.getCursor(productsSolds);
		        cursorString = cursor.toWebSafeString();
		        Iterator<ProductSold> iterator = productsSoldsCopy.iterator();	
		        while(iterator.hasNext()){
		        	ProductSold productSold = iterator.next();
		        	ProductSoldDTO productSDTO = new ProductSoldDTO();
		        	productSDTO.setCode(productSold.getIdProduct());
		        	productSDTO.setQuantity(productSold.getQuantity());
		        	productSDTO.setTitle(productSold.getTitle());
		        	productSDTO.setUnitPrice(productSold.getUnitPrice());
		        	temp.add(productSDTO);
		        }
		        result = new ResultDTO<ProductSoldDTO>();
		        result.setCursorString(cursorString);
		        result.setList(temp);
			}
			
		}catch (Exception e) {
	      e.printStackTrace();
	      result = null;
	    }
		finally{
			q.closeAll();
			pm.close();
		}
		return result;
	}
	
	@SuppressWarnings("unchecked")
	public static Integer getProductsSoldQuantity(String userAName,Long idReport){
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Integer result = 0;
		List<ProductSold> productsSolds = null;
		KeyFactory.Builder keyBuilder =
			new KeyFactory.Builder(UserAccount.class.getSimpleName(), userAName);
			keyBuilder.addChild(SaleReport.class.getSimpleName(), idReport).addChild(SaleReportIndex.class.getSimpleName(), idReport);
			Key reportKey = keyBuilder.getKey();
		Query q = pm.newQuery(ProductSold.class);
		q.setFilter("saleRIndex == :reportKey");
		try{
			productsSolds = (List<ProductSold>)q.execute(reportKey);
			if(productsSolds != null)
				result = productsSolds.size();
			
		}catch (Exception e) {
	      e.printStackTrace();
	      result = null;
	    }
		finally{
			q.closeAll();
			pm.close();
		}
		return result;
	}
	
	public static SaleReport createSaleReportDB(SaleReportDTO saleReportDTO){
		SaleReport saleReport = new SaleReport();
		saleReport.setTotal(saleReportDTO.getAmount());
		saleReport.setDate(new Date());
		saleReport.setCustomerID(saleReportDTO.getCustomerID());
		saleReport.setSellerName(saleReportDTO.getSellerUserName());
		return saleReport;
    }
	
	
}
